#ifndef __THERAD__PIPE__H__
#define __THERAD__PIPE__H__

#include <mutex>
#include <functional>
#include <list>
#include <vector>
#include <memory>
#include <thread>
#include <condition_variable>

namespace simple_renderer{

class MessageData{
public:
    MessageData(){}
    virtual ~MessageData(){}
};

template<typename T>
class TypeMessageData : public MessageData{
public:
    explicit TypeMessageData(T *data) : _data(data){}
    const T& data() const { return _data; }
    T& data() { return _data; }
private:
    T _data;
};

template<typename T>
class UniqueRefMessageData : public MessageData{
public:
    explicit UniqueRefMessageData(T *data) : _data(data){}
    const std::unique_ptr<T>& data() const { return _data; }
    std::unique_ptr<T>& data() { return _data; }
private:
    std::unique_ptr<T> _data;
};

struct Message{
    Message() : id(0), data(nullptr), handler(nullptr),
                cond_mux(nullptr), cond(nullptr), sync(false){}

    Message(const Message &msg){
        this->id = msg.id;
        this->data = msg.data;
        this->handler = msg.handler;
        this->sync = msg.sync;
        this->ready = msg.ready;
        this->cond_mux = msg.cond_mux;
        this->cond = msg.cond;
    }

    int id;
    MessageData * data;
    std::function<void(MessageData *)> handler;

    bool sync;
    std::shared_ptr<uint8_t> ready;
    std::shared_ptr<std::mutex> cond_mux;
    std::shared_ptr<std::condition_variable> cond;
};

typedef enum {
    kWait_Error,
    kWait_Timeout,
    kWait_Signaled
} WaitRes;

class ThreadPipe{
public:
    ThreadPipe();
    virtual ~ThreadPipe();

    void StartTask();
    void StopTask();

    void Post(std::function<void(MessageData *)> handler, MessageData * data);
    void PostSync(std::function<void(MessageData *)> handler, MessageData * data);

    void SetMsgHandler(std::function<void(Message)> handler){
        _msg_handler = handler;
    };
//    void RemoveTask();
    void ClearTasks();

protected:
    void Process();
    WaitRes Wait(int wait_ms);
    int OpenPipe();
    int ClosePipe();
    int WakeupPipe();
    int ResetSignalPipe();

    void InsertHeadTask(Message msg);

protected:

    std::mutex _pipe_mux;
    std::list<Message> _msg_list;
    std::vector<Message> _msg_handle_vec;

    std::unique_ptr<std::thread> _thread;
    bool _stop_thread;

    int _fd[2];
    bool _signaled;
    std::mutex _sig_mux;

    std::function<void(Message)> _msg_handler;

    bool _clear_tasks;
};

}

#endif